#include <signal.h>
#include <time.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

#include "database.h"

#include "log_print.h"

#include "cJSON.h"
#include "common.h"
#include "ll.h"

#include "mqtt_client.h"

#define TEST_DATABASE /* 用于控制测试代码是否编译 */

// // 全局变量和同步对象
// pthread_mutex_t database_init_lock;
// pthread_cond_t database_init_cond;
// static int database_thread_initialized = 1;   // 1: 没有初始化完； 0：初始化完

enum
{
    E_DB_INIT,     /* 打开数据库和初始化 */
    E_DB_DEV_LIST, /* 读取数据库中设备列表 */
    E_DB_DEV_ATTR, /* 读取数据库中设备属性表 */
    E_DB_RUN       /* 数据库正常运行 */
};

database_json_t db_config;
database_json_t db_config_default = {"tcp://localhost:1883", "./egw_db", HISTORY_LOG_DAY, "+0800", 0, 1, 1, 0, 0, -1};

//"SELECT * FROM sqlite_master WHERE type='table'"          /* 查询数据库中所有的表 */
#define SELECT_TALBE_GET_COUNT "SELECT COUNT(%s) FROM %s" /* 获取一个表里面有多少行 */
#define SELECT_TALBE_ALL "SELECT * FROM "                 /* 选择一个表的所有 */

static sqlite3 *g_db = 0;

int get_next_serial_num(char *t_name, int *p_num);
int db_update_into_table(char *str_sql);

struct dev_list_node_s
{
    cJSON *jn_dev;
    cJSON *jn_realtime_data;
};

ll_t *model_list; /* list，存储model_list_node_s，是设备模型和设备列表的总list */

/**
 * @brief  初始化存储设备列表的list
 * @param  null
 * @retval null
 */
int model_list_init(void)
{
    log_printf(MSG_DEBUG, "model_list_init");

    model_list = ll_new(ll_no_teardown);

    return 0;
}

/**
 * @brief  动态申请model_list_node_s内存
 * @param  null
 * @retval null
 */
struct model_list_node_s *creat_model_list_node_s(void)
{
    struct model_list_node_s *p;

    p = (struct model_list_node_s *)malloc(sizeof(struct model_list_node_s));

    if (p)
    {
        memset(p, 0x00, sizeof(struct model_list_node_s));
    }
    else
    {
        LOG_PRINTF_ERROR( "%s", __FUNCTION__);
    }

    return p;
}

/**
 * @brief  创建list结点，存储model_list_mode
 * @param  name 模型名
 * @retval null
 */
int creat_model_list_node(char *name)
{
    struct model_list_node_s *p = NULL;

    if (NULL == name)
        return -1;

    p = creat_model_list_node_s();

    if (NULL == p)
        return -2;

    if (strlen(name) > sizeof(p->model_name))
        return -3;

    memcpy(p->model_name, name, strlen(name));

    ll_insert_last(model_list, p);

    return 0;
}

/**
 * @brief  清除存储设备列表的list
 * @param  null
 * @retval null
 */
int model_list_destroy(void)
{
    int i;
    struct model_list_node_s *p;
    ll_t *list = model_list;

    log_printf(MSG_DEBUG, "model_list_destroy");

    if (NULL == list)
        return -1;

    for (i = 0; i < list->len; i++)
    {
        p = (struct model_list_node_s *)ll_get_n(list, i);
        if (NULL == p)
            continue;

        if (NULL != p->jn_dev)
        {
            cJSON_Delete(p->jn_dev);
            p->jn_dev = NULL;
        }
        if (NULL != p->jn_model)
        {
            cJSON_Delete(p->jn_model);
            p->jn_model = NULL;
        }
        if (NULL != p->jn_realtime_data)
        {
            cJSON_Delete(p->jn_realtime_data);
            p->jn_realtime_data = NULL;
        }

        if(NULL != p->jn_soe_subscribe)
        {
            cJSON_Delete(p->jn_soe_subscribe);
            p->jn_soe_subscribe = NULL;
        }

        free(p);
        p = NULL;
    }

    ll_delete(model_list);
    model_list = NULL;

    return 0;
}

/**
 * @brief  从数据库中获取以name开头的所有表名
 * @param  null
 * @retval null
 */
int get_table_start_with_name(char *name, sqlite3_callback cb_fun, void *para)
{
    char str_sql[512];
    int rtn;

    if (NULL == name)
        return -1;

    memset(str_sql, 0x00, sizeof(str_sql));
    sprintf(str_sql, SELECT_TABLE_NAME_LIKE, name);
    // printf("get_table_start_with_name sql = %s \n", str_sql);
    rtn = db_select_with_cb(str_sql, cb_fun, para);

    return rtn;
}

/**
 * @brief  从数据库中读取模型表，模型表是以mode_开头的表 回调函数
 * @param  null
 * @retval null
 */
static int get_all_mode_name_cb(void *para, int argc, char **argv, char **azColName)
{
    // int i;
    char *p = NULL;
    cJSON *Array;

    if ((NULL != para) && (NULL != (argv[0])))
    {
        Array = (cJSON *)para;
        p = strstr(argv[0], MODE_TABLE_HEAD);
        if (p)
        {
            p += strlen(MODE_TABLE_HEAD);
            cJSON_AddItemToArray(Array, cJSON_CreateString(p));
        }
    }

#if 0 /* 调试 */
    printf("column = %d \n", argc);
    for(i = 0; i < argc; i++){
        printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
    }
#endif

    return 0;
}

/**
 * @brief  从数据库中读取模型表，模型表是以mode_开头的表
 * @param  null
 * @retval null
 */
int get_all_mode_name(void *para)
{
    get_table_start_with_name(MODE_TABLE_HEAD, get_all_mode_name_cb, para);

    return 0;
}

/**
 * @brief  从数据库中读取模型内容 回调函数
 * @param  null
 * @retval null
 */
static int get_mode_info_cb(void *para, int argc, char **argv, char **azColName)
{
    int i;
    cJSON *object = NULL;
    cJSON *Array = NULL;

    if (NULL == para)
        return 0;

    Array = (cJSON *)para;
    object = cJSON_CreateObject();

    for (i = 0; i < argc; i++)
    {
        if (0 != i)
        { /* 不需要sn字段 */
            cJSON_AddItemToObject(object, azColName[i], cJSON_CreateString(argv[i] ? argv[i] : "NULL"));
        }
    }
    cJSON_AddItemToArray(Array, object);

#if 0 /* 调试 */
    printf("column = %d \n", argc);
    for(i = 0; i < argc; i++){
        printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
    }
#endif

    return 0;
}

/**
 * @brief  从数据库中读取模型内容
 * @param  table_name 表名
 * @param  para 传递的是cJSON *Array类型
 * @retval null
 */
int get_mode_info(char *table_name, void *para)
{
    char str_sql[512];
    int rtn;

    if (NULL == table_name)
        return -1;

    memset(str_sql, 0x00, sizeof(str_sql));
    sprintf(str_sql, SELECT_TABLE, "*", table_name);
    log_printf(MSG_DEBUG, "get model: %s", str_sql);
    rtn = db_select_with_cb(str_sql, get_mode_info_cb, para);

    return rtn;
}

/**
 * @brief  从数据库中读取模型内容
 * @param  table_name 表名
 * @param  para 传递的是cJSON *Array类型
 * @retval null
 */
int get_mode_info_key(char *table_name, void *para, char *name)
{
    char str_sql[512];
    int rtn;

    if ((NULL == table_name) || (NULL == name))
        return -1;

    memset(str_sql, 0x00, sizeof(str_sql));
    sprintf(str_sql, SELECT_TABLE_NAME, "*", table_name, name);
    log_printf(MSG_DEBUG, "get model: %s", str_sql);
    rtn = db_select_with_cb(str_sql, get_mode_info_cb, para);

    return rtn;
}

/**
 * @brief  从数据库中读取设备的GUID 回调函数
 * @param  null
 * @retval null
 */
static int get_dev_guid_cb(void *para, int argc, char **argv, char **azColName)
{
    int i;

    if (NULL == para)
        return 0;

    for (i = 0; i < argc; i++)
    {
        /* 获取guid */
        if (0 == memcmp(azColName[i], STR_GUID, strlen(STR_GUID)) && (strlen(azColName[i]) == strlen(STR_GUID)))
        {
            memcpy(para, argv[i], strlen(argv[i]));
            break;
        }
    }

#if 0 /* 调试 */
    printf("column = %d \n", argc);
    for(i = 0; i < argc; i++){
        printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
    }
#endif

    return 0;
}

/**
 * @brief  从数据库中读取设备的GUID，根据mode、port、addr、desc来搜索
 * @param  table_name 表名
 * @param  mode 设备模型名
 * @param  port 设备port
 * @param  addr 设备addr
 * @param  desc 设备desc
 * @param  para 保存GUID
 * @retval null
 */
int get_dev_guid(char *table_name, char *mode, char *port, char *addr, char *desc, void *para)
{
    char str_sql[2048];
    int rtn;

    if (NULL == table_name)
        return -1;

    memset(str_sql, 0x00, sizeof(str_sql));
    if (0 != strlen(desc))
    {
        sprintf(str_sql, SELECT_TABLE_GET_GUID, "*", table_name, mode, port, addr, desc);
    }
    else
    {
        sprintf(str_sql, SELECT_TABLE_GET_GUID_NO_DESC, "*", table_name, mode, port, addr);
    }
    log_printf(MSG_DEBUG, "get guid: %s", str_sql);
    rtn = db_select_with_cb(str_sql, get_dev_guid_cb, para);

    return rtn;
}

/**
 * @brief  从数据库设备表中读取某个设备的注册appname 回调函数
 * @param  null
 * @retval null
 */
static int get_app_name_from_dev_table_cb(void *para, int argc, char **argv, char **azColName)
{
    int i;

    if (NULL == para)
        return 0;

    for (i = 0; i < argc; i++)
    {
        /* 获取appname */
        if (0 == memcmp(azColName[i], STR_APPNAME, strlen(STR_APPNAME)) &&
            (strlen(azColName[i]) == strlen(STR_APPNAME)))
        {
            if (strlen(argv[i]))
            {
                memcpy(para, argv[i], strlen(argv[i]));
            }
            break;
        }
    }

#if 0 /* 调试 */
    printf("column = %d \n", argc);
    for(i = 0; i < argc; i++){
        printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
    }
#endif

    return 0;
}

/**
 * @brief  从数据库设备表中读取某个设备的注册appname
 * @param  null
 * @retval null
 */
int get_app_name_from_dev_table(char *table, char *dev, char *name)
{
    char str_sql[1024];
    int rtn;

    if ((NULL == table) || (NULL == dev) || (NULL == name))
        return -1;

    memset(str_sql, 0x00, sizeof(str_sql));
    sprintf(str_sql, SELECT_TABLE_GET_APP_NAME, STR_APPNAME, table, dev);
    rtn = db_select_with_cb(str_sql, get_app_name_from_dev_table_cb, name);

    return rtn;
}

/**
 * @brief  从设备名获取模型名
 * @param  null
 * @retval null
 */
int get_model_from_dev(char *dev, char *model)
{
    char *p;

    if ((NULL == dev) || (NULL == model))
        return -1;

    p = strrchr(dev, '_');
    if (NULL == p)
    {
        return -2;
    }

    memcpy(model, dev, (p - dev));
    // printf("model = %s \n", model);

    return 0;
}

/**
 * @brief  从数据库中读取frozen_type一样的所有数据 回调函数
 * @param  null
 * @retval null
 */
static int get_frozen_type_data_cb(void *para, int argc, char **argv, char **azColName)
{
    int i;
    cJSON *Array;
    cJSON *jn;

    if (NULL == para)
        return 0;

    Array = (cJSON *)para;
    jn = cJSON_CreateObject();

    for (i = 0; i < argc; i++)
    {
        cJSON_AddItemToObject(jn, azColName[i], cJSON_CreateString(argv[i]));
    }
    cJSON_AddItemToArray(Array, jn);

#if 0 /* 调试 */
    printf("column = %d \n", argc);
    for(i = 0; i < argc; i++){
        printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
    }
#endif

    return 0;
}

/**
 * @brief  从数据库中读取frozen_type一样的所有数据，如果属性名property不为空，就同时过滤属性名
 * @param  table_name 表名
 * @param  frozen_type 冻结类型
 * @param  property 属性名
 * @param  array 保存查询结果
 * @param  start_t 起始时间
 * @param  start_t 结束时间
 * @retval null
 */
int get_frozen_type_and_property_data(char *table_name, char *frozen_type, cJSON *property, cJSON *array, char *start_t,
                                      char *end_t, char *time_type)
{
    char str_sql[16 * 1024];
    char buff[256];
    int size = 0;
    int i = 0;
    int j = 0;
    int rtn;
    char *str_and_s = " AND (";
    char *str_and_e = ")";

    if ((NULL == table_name) || (NULL == frozen_type) || (NULL == property) || (NULL == array) || (NULL == start_t) ||
        (NULL == end_t))
        return -1;

    if (0 == table_exist_check(table_name))
        return -2;

    memset(str_sql, 0x00, sizeof(str_sql));
    sprintf(str_sql, SELECT_TABLE_FROZENTYPE, "*", table_name, frozen_type, time_type, start_t, time_type, end_t);
    log_printf(MSG_INFO, "get_frozen_type_and_property_data: %s", str_sql);

    size = cJSON_GetArraySize(property);
    if (size)
    { /* 需要过滤property */
        j = strlen(str_sql);
        memcpy(&str_sql[j], str_and_s, strlen(str_and_s));
        j += strlen(str_and_s);
        for (i = 0; i < size; i++)
        {
            memset(buff, 0x00, sizeof(buff));
            cJSON *item1 = cJSON_GetArrayItem(property, i);
            if ((0 == item1) || (0 == item1->valuestring))
            {
                continue;
            }
            if (0 == i)
            {
                sprintf(buff, "name = '%s'", item1->valuestring);
            }
            else
            {
                sprintf(buff, " OR name = '%s'", item1->valuestring);
            }

            if ((j + strlen(buff)) >= sizeof(str_sql))
            {
                LOG_PRINTF_ERROR( "func(%s) str_sql overflow !", __FUNCTION__);
                break;
            }
            memcpy(&str_sql[j], buff, strlen(buff));
            j += strlen(buff);
        }
        memcpy(&str_sql[j], str_and_e, strlen(str_and_e));
        j += strlen(str_and_e);
    }

    log_printf(MSG_DEBUG, "get_frozen_type_data: %s", str_sql);
    rtn = db_select_with_cb(str_sql, get_frozen_type_data_cb, array);

    return rtn;
}

/**
 * @brief  从数据库中读取acq_files数据 回调函数
 * @param  null
 * @retval null
 */
static int get_acq_files_data_cb(void *para, int argc, char **argv, char **azColName)
{
    int i;
    cJSON *Array;
    cJSON *jn;

    if (NULL == para)
        return 0;

    Array = (cJSON *)para;
    jn = cJSON_CreateObject();

    for (i = 0; i < argc; i++)
    {
        cJSON_AddItemToObject(jn, azColName[i], cJSON_CreateString(argv[i]));
    }
    cJSON_AddItemToArray(Array, jn);

#if 0 /* 调试 */
    printf("column = %d \n", argc);
    for(i = 0; i < argc; i++){
        printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
    }
#endif

    return 0;
}

/**
 * @brief  从数据库中读取acq_files数据
 * @param  t_name 表名
 * @param  property_name 属性名
 * @param  property_val 属性值
 * @param  array 保存查询结果
 * @retval null
 */
int get_acq_files_data(char *t_name, char *property_name, char *property_val, cJSON *array)
{
    char str_sql[1024];
    int rtn;

    if ((NULL == t_name) || (NULL == property_name) || (NULL == property_val) || (NULL == array))
        return -1;

    if (0 == table_exist_check(t_name))
        return -2;

    memset(str_sql, 0x00, sizeof(str_sql));
    sprintf(str_sql, SELECT_TABLE_ACQ_FILES, "*", t_name, property_name, property_val);

    log_printf(MSG_DEBUG, "get_acq_files_data: %s", str_sql);
    rtn = db_select_with_cb(str_sql, get_acq_files_data_cb, array);

    return rtn;
}

/**
 * @brief  从数据库中读取acq_files数据
 * @param  t_name 表名
 * @param  property_name 属性名
 * @param  property_val 属性值
 * @param  property_name2 属性名
 * @param  property_val2 属性值
 * @param  array 保存查询结果
 * @retval null
 */
int get_acq_files_data2(char *t_name, char *property_name, char *property_val, char *property_name2,
                        char *property_val2, cJSON *array)
{
    char str_sql[1024];
    int rtn;

    if ((NULL == t_name) || (NULL == property_name) || (NULL == property_val) || (NULL == property_name2) ||
        (NULL == property_val2) || (NULL == array))
        return -1;

    if (0 == table_exist_check(t_name))
        return -2;

    memset(str_sql, 0x00, sizeof(str_sql));
    sprintf(str_sql, SELECT_TABLE_ACQ_FILES2, "*", t_name, property_name, property_val, property_name2, property_val2);

    log_printf(MSG_DEBUG, "get_acq_files_data2: %s", str_sql);
    rtn = db_select_with_cb(str_sql, get_acq_files_data_cb, array);

    return rtn;
}

/**
 * @brief  从数据库中读取设备/APP注册关系 回调函数
 * @param  null
 * @retval null
 */
static int get_dev_app_regist_info_cb(void *para, int argc, char **argv, char **azColName)
{
    int i;
    cJSON *object = NULL;
    cJSON *Array = NULL;

    if (NULL == para)
        return 0;

    Array = (cJSON *)para;
    object = cJSON_CreateObject();

    for (i = 0; i < argc; i++)
    {
        if (0 == strcmp(azColName[i], "guid"))
        {
            cJSON_AddItemToObject(object, "guid", cJSON_CreateString(argv[i]));
        }
        else
        {
            if (NULL != argv[i])
            {
                cJSON_AddItemToObject(object, azColName[i], cJSON_CreateString(argv[i]));
            }
            else
            {
                cJSON_AddItemToObject(object, azColName[i], cJSON_CreateString("NULL"));
            }
        }
    }
    cJSON_AddItemToArray(Array, object);

#if 0 /* 调试 */
    printf("column = %d \n", argc);
    for(i = 0; i < argc; i++){
        printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
    }
#endif

    return 0;
}

/**
 * @brief  从数据库中读取设备/APP注册关系
 * @param  table_name 表名
 * @param  para 传递的是cJSON *Array类型
 * @retval null
 */
int get_dev_app_regist_info(char *table_name, int index, void *para)
{
    char str_sql[256];
    int rtn;
    // char buff[32];

    if (NULL == table_name)
        return -1;

    memset(str_sql, 0x00, sizeof(str_sql));
    sprintf(str_sql, SELECT_LIMIT_OFFSET, "*", table_name, 1, index); /* 一次就取一个column数据 */
    log_printf(MSG_DEBUG, "get dev_app_regist: %s", str_sql);
    rtn = db_select_with_cb(str_sql, get_dev_app_regist_info_cb, para);

    return rtn;
}

/**
 * @brief  查询数据库中某个表的column个数 回调函数
 * @param  null
 * @retval null
 */
static int get_table_column_cb(void *para, int argc, char **argv, char **azColName)
{
    // int i;
    int *column = (int *)para;

    if (NULL == para)
        return 0;

    if (argc)
    {
        *column = atoi(argv[0]); /* 返回column个数 */
    }

#if 0 /* 调试 */
    printf("column = %d \n", argc);
    for(i = 0; i < argc; i++){
        printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
    }
#endif

    return 0;
}

/**
 * @brief  查询数据库中某个表的column个数
 * @param  table_name 表名
 * @param  para 传递的是int *类型，返回column个数
 * @retval null
 */
int get_table_column(char *table_name, void *para)
{
    char str_sql[256];
    int rtn;

    if (NULL == table_name)
        return -1;

    memset(str_sql, 0x00, sizeof(str_sql));
    sprintf(str_sql, SELECT_COLUMN, "*", table_name);
    log_printf(MSG_DEBUG, "get model: %s", str_sql);
    rtn = db_select_with_cb(str_sql, get_table_column_cb, para);

    return rtn;
}

/**
 * @brief  查询数据库中设备表的最大 guid 回调函数
 * @param  null
 * @retval null
 */
static int get_max_guid_cb(void *para, int argc, char **argv, char **azColName)
{
    if (NULL == para)
        return 0;

#if 0 /* 调试 */
    log_printf(MSG_INFO, "get_max_guid_cb:argc[%d]", argc);
    log_printf(MSG_INFO, "get_max_guid_cb:argv[%s]", argv[0]);
    log_printf(MSG_INFO, "get_max_guid_cb:azColName[%s]", azColName[0]);
#endif

    if (argv[0])
    {
        memcpy(para, argv[0], strlen(argv[0]));
        return 0;
    }

    return 0;        // 不要问为啥返回0，是因为防止打印过多信息，外部不是通过返回值判断的，是通过 para 参数判断的。
}

/**
 * @brief  查询数据库中设备表的最大guid
 * @param  table_name 表名
 * @param  para 传递的是int *类型，返回最大的guid
 * @retval null
 */
int get_max_guid(char *table_name, void *para)
{
    char str_sql[128];
    int rtn;

    if (NULL == table_name)
        return -1;

    memset(str_sql, 0x00, sizeof(str_sql));
    sprintf(str_sql, SELECT_MAX_GUID, table_name);
    log_printf(MSG_DEBUG, "get max guid: %s", str_sql);
    rtn = db_select_with_cb(str_sql, get_max_guid_cb, para);

    return rtn;
}

/**
 * @brief  查询数据库中某个表的column个数 回调函数
 * @param  null
 * @retval null
 */
static int get_table_one_property_cb(void *para, int argc, char **argv, char **azColName)
{
    // int i;
    char *port = (char *)para;

    if (NULL == para)
        return 0;

    if (argc)
    {
        memcpy(port, argv[0], strlen(argv[0]));
    }

#if 0 /* 调试 */
    printf("column = %d \n", argc);
    for(i = 0; i < argc; i++){
        printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
    }
#endif

    return 0;
}

/**
 * @brief  从数据库中读取设备/APP注册关系
 * @param  table_name 表名
 * @param  para 传递的是cJSON *Array类型
 * @retval null
 */
int get_table_one_property(char *table_name, int index, char *property, void *para)
{
    char str_sql[256];
    int rtn;
    // char buff[32];

    if (NULL == table_name)
        return -1;

    memset(str_sql, 0x00, sizeof(str_sql));
    sprintf(str_sql, SELECT_LIMIT_OFFSET, property, table_name, 1, index); /* 一次就取一个column数据 */
    log_printf(MSG_DEBUG, "get dev_app_regist: %s", str_sql);
    rtn = db_select_with_cb(str_sql, get_table_one_property_cb, para);

    return rtn;
}

/**
 * @brief  查询表是否存在 回调函数
 * @param  t_name 表名
 * @retval 1表示存在，0表示不存在
 */
static int table_exist_check_cb(void *para, int argc, char **argv, char **azColName)
{
    // int i;
    int *exist = (int *)para;

    if (NULL == para)
        return 0;

    if (argc)
    {
        *exist = atoi(argv[0]);
    }

#if 0 /* 调试 */
    printf("column = %d \n", argc);
    for(i = 0; i < argc; i++){
        printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
    }
#endif

    return 0;
}

/**
 * @brief  查询表是否存在
 * @param  t_name 表名
 * @retval 1表示存在，0表示不存在
 */
int table_exist_check(char *t_name)
{
    int iret;
    char str_sql[512];
    int exist = 0;

    if (NULL == g_db)
    {
        return -1;
    }

    if (NULL == t_name)
    {
        return -2;
    }

    /*增加不区分大小写判断*/
    memset(str_sql, 0x00, sizeof(str_sql));
    sprintf(str_sql, TABLE_EXIAT_CHECK, t_name);
    iret = db_select_with_cb(str_sql, table_exist_check_cb, &exist);
    if (0 != iret)
    {
        return -3;
    }

    if (1 == exist)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

/**
 * @brief  查询表是否存在
 * @param  t_name 表名
 * @retval 1表示存在，0表示不存在 2表示存在名字相同但大小写不同的表
 */
int table_exist_check_model(char *t_name)
{
    int iret;
    char str_sql[512];
    int exist = 0;

    if (NULL == g_db)
    {
        return -1;
    }

    if (NULL == t_name)
    {
        return -2;
    }

    /*增加不区分大小写判断*/
    memset(str_sql, 0x00, sizeof(str_sql));
    sprintf(str_sql, TABLE_EXIAT_CHECK_COLLATE_NOCASE, t_name);
    iret = db_select_with_cb(str_sql, table_exist_check_cb, &exist);
    if (0 != iret)
    {
        return -3;
    }

    if (1 == exist)
    {

        memset(str_sql, 0x00, sizeof(str_sql));
        sprintf(str_sql, TABLE_EXIAT_CHECK, t_name);
        iret = db_select_with_cb(str_sql, table_exist_check_cb, &exist);

        if (0 != iret)
        {
            return -3;
        }

        if (1 == exist)
        {
            return 1;
        }
        else
        {
            return 2;
        }
    }
    else
    {
        return 0;
    }
}

/**
 * @brief  如果不存在数据库表，则创建
 * @param  sql 表结构
 * @param  t_name 表名
 * @retval null
 */
int creat_table_if_not_exist(char *sql, char *t_name)
{
    int iret;
    char buff[2048];
    int exist = 0;

    if (NULL == g_db)
    {
        return -1;
    }

    if ((NULL == sql) || (NULL == t_name))
    {
        return -2;
    }

    exist = table_exist_check(t_name);
    if (1 == exist)
    {
        log_printf(MSG_VERBOSE, "func(%s), table[%s] already exist", __FUNCTION__, t_name);
        return 0;
    }

    memset(buff, 0x00, sizeof(buff));
    sprintf(buff, sql, t_name);
    iret = api_create_sqlite_table(g_db, buff);

    if (0 != iret)
    {
        return -4;
    }

    return 0;
}

/**
 * @brief  如果不存在数据库表，则创建
 * @param  sql 表结构
 * @param  t_name 表名
 * @retval null
 */
int creat_table_if_not_exist_model(char *sql, char *t_name)
{
    int iret;
    char buff[2048];
    int exist = 0;

    if (NULL == g_db)
    {
        return -1;
    }

    if ((NULL == sql) || (NULL == t_name))
    {
        return -2;
    }

    exist = table_exist_check_model(t_name);
    if (1 == exist)
    {
        log_printf(MSG_VERBOSE, "func(%s), table[%s] already exist", __FUNCTION__, t_name);
        return 0;
    }

    if (2 == exist)
    {
        log_printf(MSG_VERBOSE, "func(%s), same name but different capitalization table[%s] already exist",
                   __FUNCTION__, t_name);
        return 2;
    }

    memset(buff, 0x00, sizeof(buff));
    sprintf(buff, sql, t_name);
    iret = api_create_sqlite_table(g_db, buff);

    if (0 != iret)
    {
        return -4;
    }

    return 0;
}

/**
 * @brief 保存一个属性信息到模型表
 * @param  t_name 表名
 * @retval null
 */
int save_property_to_model_table(char *t_name, struct model_property_s *p)
{
    char str_sql[4096];
    int sn = 0;

    if ((NULL == t_name) || (NULL == p))
    {
        return -1;
    }

    get_next_serial_num(t_name, &sn);

    memset(str_sql, 0x00, sizeof(str_sql));
    sprintf(str_sql, MODEL_PROPERTY_INSERT, t_name, sn, p->name, p->type, p->unit, p->deadzone, p->ratio, p->isreport,
            p->userdefine);

    if (db_insert_into_table(str_sql))
    {
        LOG_PRINTF_ERROR( "fun(%s) %s add to model error", __FUNCTION__, str_sql);
        return -2;
    }

    return 0;
}

/**
 * @brief 保存设备到设备表
 * @param  t_name 表名
 * @retval null
 */
int save_property_to_dev_table(char *t_name, struct dev_property_s *p)
{
    char str_sql[5120];

    if ((NULL == t_name) || (NULL == p))
    {
        return -1;
    }

    memset(str_sql, 0x00, sizeof(str_sql));

    sprintf(str_sql, DEV_PROPERTY_INSERT, t_name, p->guid, p->dev, p->model, p->port, p->addr, p->desc, p->manuID,
            p->manuName, p->ProType, p->deviceType, p->isReport, p->nodeID, p->productID, p->appname);

    if (db_insert_into_table(str_sql))
    {
        LOG_PRINTF_ERROR( "fun(%s) %s add to dev error", __FUNCTION__, str_sql);
        return -2;
    }

    return 0;
}

/**
 * @brief 保存设备到设备表
 * @param  t_name 表名
 * @retval null
 */
int save_property_to_dev_table_V2(char *t_name, struct dev_property_s *p)
{
    char str_sql[5120];

    if ((NULL == t_name) || (NULL == p))
    {
        return -1;
    }

    memset(str_sql, 0x00, sizeof(str_sql));

    sprintf(str_sql, DEV_PROPERTY_INSERT_V2, t_name, p->dev, p->model, p->port, p->addr, p->desc, p->manuID,
            p->manuName, p->ProType, p->deviceType, p->isReport, p->nodeID, p->productID, p->appname);

    if (db_insert_into_table(str_sql))
    {
        LOG_PRINTF_ERROR( "fun(%s) %s add to dev error", __FUNCTION__, str_sql);
        return -2;
    }

    return 0;
}

/**
 * @brief  冻结数据写入数据库，使用INSERT的方式
 * @param  table_name 表名
 * @param  name 属性名
 * @param  value 属性值
 * @param  timestamp 数据时标
 * @param  frozentype 冻结类型
 * @param  timestartgather 采集开始时间
 * @param  timeendgather 采集结束时间
 * @param  additionalcheck 附加校验
 * @retval null
 */
int save_frozen_data_to_db(char *t_name, char *name, char *value, char *timestamp, char *frozentype,
                           char *timestartgather, char *timeendgather, char *additionalcheck)
{
    char str_sql[4096];

    if ((NULL == t_name) || (NULL == name) || (NULL == value) || (NULL == timestamp) || (NULL == frozentype) ||
        (NULL == timestartgather) || (NULL == timeendgather) || (NULL == additionalcheck))
    {
        return -1;
    }

    memset(str_sql, 0x00, sizeof(str_sql));
    /* h->value为空是否要处理str_sql，注意这里主键sn要根据数据库里面现有多少记录来累加 */
    sprintf(str_sql, HISTORY_FROZEN_INSERT, t_name, frozentype, timestamp, timestartgather, timeendgather,
            additionalcheck, name, value);

    if (db_insert_into_table(str_sql))
    {
        LOG_PRINTF_ERROR( "fun(%s) %s add to history error", __FUNCTION__, str_sql);
        return -2;
    }

    return 0;
}

/**
 * @brief  冻结数据写入数据库，使用REPLACE的方式
 * @param  t_name 表名
 * @param  name 属性名
 * @param  value 属性值
 * @param  timestamp 数据时标
 * @param  frozentype 冻结类型
 * @param  timestartgather 采集开始时间
 * @param  timeendgather 采集结束时间
 * @param  additionalcheck 附加校验
 * @retval null
 */
int replace_frozen_data_to_db(char *t_name, char *name, char *value, char *timestamp, char *frozentype,
                              char *timestartgather, char *timeendgather, char *additionalcheck)
{
    char *str_sql = NULL;
    int len = 0;
    int rtn = 0;

    if ((NULL == t_name) || (NULL == name) || (NULL == value) || (NULL == timestamp) || (NULL == frozentype) ||
        (NULL == timestartgather) || (NULL == timeendgather) || (NULL == additionalcheck))
    {
        rtn = -1;
        goto CLEAN_UP;
    }

    len = 128 + strlen(REPLACE_HISTORY_FROZEN) + strlen(t_name) + strlen(frozentype) + strlen(timestamp) +
          strlen(timestartgather) + strlen(timeendgather) + strlen(additionalcheck) + strlen(name) + strlen(value);
    str_sql = (char *)malloc(len);
    if (NULL == str_sql)
    {
        rtn = -2;
        goto CLEAN_UP;
    }

    memset(str_sql, 0x00, len);
    /* h->value为空是否要处理str_sql */
    sprintf(str_sql, REPLACE_HISTORY_FROZEN, t_name, frozentype, timestamp, timestartgather, timeendgather,
            additionalcheck, name, value);

    if (db_update_into_table(str_sql))
    {
        LOG_PRINTF_ERROR( "fun(%s) %s add to history error", __FUNCTION__, str_sql);
        rtn = -3;
        goto CLEAN_UP;
    }

CLEAN_UP:
    if (str_sql)
    {
        free(str_sql);
        str_sql = NULL;
    }

    return rtn;
}
							  
/**
 * @brief  获取时间戳字符串
 * @param  null
 * @retval null
 */
int get_timestamp(char *buff)
{
    time_t t;
    struct tm *t_tm;
    struct timeval tv;
    int usec_3;

    if (NULL == buff)
        return -1;

    gettimeofday(&tv, NULL);
    usec_3 = tv.tv_usec / 1000; /* 只保留高3位 */

    time(&t); /* This function get a timestamp in seconds_from_1970.microsoconds */
    t_tm = localtime(&t);
    // printf("%s: %4d-%02d-%02d \r\n", __FUNCTION__, t_tm->tm_year + 1900, t_tm->tm_mon + 1, t_tm->tm_mday);

    sprintf(buff, "%4d-%02d-%02dT%02d:%02d:%02d.%.3d%s", t_tm->tm_year + 1900, t_tm->tm_mon + 1, t_tm->tm_mday,
            t_tm->tm_hour, t_tm->tm_min, t_tm->tm_sec, usec_3, db_config.time_zone);

    return 0;
}

/**
 * @brief  从数据库中读取设备的GUID，每次读取一个 回调函数
 * @param  null
 * @retval null
 */
static int get_dev_guid_one_by_one_cb(void *para, int argc, char **argv, char **azColName)
{
    if (NULL == para)
        return 0;

    if (0 == memcmp(azColName[0], STR_GUID, strlen(STR_GUID)) && (strlen(azColName[0]) == strlen(STR_GUID)))
    {
        memcpy(para, argv[0], strlen(argv[0]));
    }

#if 0 /* 调试 */
    printf("column = %d \n", argc);
    for(i = 0; i < argc; i++){
        printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
    }
#endif

    return 0;
}

/**
 * @brief  从数据库中读取设备的GUID，每次读取一个
 * @param  table_name 表名
 * @param  index 表中的第几行
 * @param  para 保存GUID
 * @retval null
 */
int get_dev_guid_one_by_one(char *table_name, int index, void *para)
{
    char str_sql[256];
    int rtn;

    if (NULL == table_name)
        return -1;

    memset(str_sql, 0x00, sizeof(str_sql));
    sprintf(str_sql, SELECT_LIMIT_OFFSET, "*", table_name, 1, index); /* 一次就取一个column数据 */
    log_printf(MSG_DEBUG, "get guid: %s", str_sql);
    rtn = db_select_with_cb(str_sql, get_dev_guid_one_by_one_cb, para);

    return rtn;
}

/**
 * @brief  从数据库中读取所有设备的GUID， 回调函数
 * @param  null
 * @retval null
 */
static int get_all_dev_guid_cb(void *para, int argc, char **argv, char **azColName)
{
    for (int i = 0; i < argc; i++)
    {
        if (NULL != argv[i])
        {
            int n = atoi(argv[i]);
            if (n == *(int *)para)
            {
                (*(int *)para)++;
            }
        }
    }

    return 0;
}

/**
 * @brief  从数据库中读取所有设备的GUID
 * @param  table_name 表名
 * @param  para 保存GUID
 * @retval null
 */
int get_all_dev_guid(char *table_name, void *para)
{
    char str_sql[128] = {'\0'};
    int rtn;

    if (NULL == table_name || NULL == para)
    {
        return -1;
    }

    sprintf(str_sql, SELECT_ALL_GUID, table_name);
    log_printf(MSG_DEBUG, "get all guid: %s", str_sql);
    rtn = db_select_with_cb(str_sql, get_all_dev_guid_cb, para);

    return rtn;
}

/**
 * @brief  从模型中获取属性名，添加到每个设备创建实时数据，json格式，以jn_realtime_data管理
 * @param  null
 * @retval null
 */
static int add_model_property_to_realtime_data(cJSON *jn_model, cJSON *jn_realtime_data)
{
    int i;
    int size;

    if ((NULL == jn_model) || (NULL == jn_realtime_data))
        return -1;

    size = cJSON_GetArraySize(jn_model);
    if (0 == size)
        return -2;

    for (i = 0; i < size; i++)
    {
        cJSON *object = cJSON_CreateObject();
        cJSON *jn1 = cJSON_GetArrayItem(jn_model, i);
        if (0 == jn1)
        {
            continue;
        }

        cJSON *name_item = cJSON_GetObjectItemCaseSensitive(jn1, STR_NAME);
        if ((0 == name_item) || (0 == name_item->valuestring))
        {
            continue;
        }
        // printf("name_item = %s \n", name_item->valuestring);

        cJSON_AddItemToObject(object, STR_TIMESTAMP, cJSON_CreateString("NULL"));
        cJSON_AddItemToObject(object, STR_VAL, cJSON_CreateString("NULL"));
        cJSON_AddItemToObject(object, STR_QUALITY, cJSON_CreateString("NULL"));
        cJSON_AddItemToObject(object, STR_INDEX, cJSON_CreateString("NULL"));

        cJSON_AddItemToObject(jn_realtime_data, name_item->valuestring, object);
    }

    return 0;
}

/**
  * @brief  每个设备创建实时数据在内存，json格式，以jn_realtime_data管理，格式如下
[{
        "dev":  "TTU1",
        "PhV_phsA":     {
                "timestamp":    "NULL",
                "value":        "NULL",
                "quality":      "NULL",
                "index":        "NULL"
        },
        "PhV_phsB":     {
                "timestamp":    "NULL",
                "value":        "NULL",
                "quality":      "NULL",
                "index":        "NULL"
        }
}, {
        "dev":  "TTU2",
        "PhV_phsA":     {
                "timestamp":    "NULL",
                "value":        "NULL",
                "quality":      "NULL",
                "index":        "NULL"
        },
        "PhV_phsB":     {
                "timestamp":    "NULL",
                "value":        "NULL",
                "quality":      "NULL",
                "index":        "NULL"
        }
}]
  * @param  null
  * @retval null
  */
int get_dev_realtime_data(void)
{
    ll_t *list = model_list;
    struct model_list_node_s *p;
    char name[128];
    char guid[128];
    int column = 0;
    int i;
    int j;

    if (NULL == list)
        return -1;

    for (i = 0; i < list->len; i++)
    {
        p = (struct model_list_node_s *)ll_get_n(list, i);
        if (p)
        {
            p->jn_realtime_data = cJSON_CreateArray();
            memset(name, 0x00, sizeof(name));
            sprintf(name, "%s%s", STR_DEV_, p->model_name);
            get_table_column(name, &column);
            // printf("func(%s) table[%s] column = %d \n", __FUNCTION__, name, column);
            for (j = 0; j < column; j++)
            {
                memset(guid, 0x00, sizeof(guid));
                get_dev_guid_one_by_one(name, j, guid);
                // printf("func(%s) guid = %s \n", __FUNCTION__, guid);
                if (strlen(guid))
                {
                    cJSON *object = cJSON_CreateObject();
                    char buff[128];
                    memset(buff, 0x00, sizeof(buff));
                    sprintf(buff, "%s_%s", p->model_name, guid);
                    cJSON_AddItemToObject(object, STR_DEV, cJSON_CreateString(buff));
                    /* 添加所有模型的属性到设备实时数据json */
                    add_model_property_to_realtime_data(p->jn_model, object);
                    cJSON_AddItemToArray(p->jn_realtime_data, object);
                }
            }
        }

#if 0 /* 调试 */
        char *payload = cJSON_Print(p->jn_realtime_data);
        printf("func(%s) %s realtime_data = %s \n", __FUNCTION__, name, payload);
        if (payload) cJSON_free(payload);
#endif
    }

    return 0;
}


/**
 * @brief  从设备表中获取一个空闲的guid
 * @param  null
 * @retval null
 */
int get_unused_guid(char *table_name, char *guid)
{
    if ((NULL == table_name) || (NULL == guid))
        return -1;

    int index = 1;

    /* 将设备表中所有guid获取到 */
    get_all_dev_guid(table_name, &index);
    sprintf(guid, "%d", index);

    return 0;
}

/**
 * @brief  从设备表中获取一个空闲的guid
 * @param  null
 * @retval -1: 参数有误 0: 查询成功
 */
int get_unused_guid_V2(char *table_name, char *guid)
{
    if ((NULL == table_name) || (NULL == guid))
        return -1;

    char max_guid[128];
    memset(max_guid, '\0', sizeof(max_guid));
    get_max_guid(table_name, max_guid);
    if (strlen(max_guid) == 0)
    {
        /* 设备表里面是空的，guid从1开始 */
        memcpy(max_guid, "0", strlen("0"));
    }

    int num = atoi(max_guid);
    num++;
    sprintf(guid, "%d", num);

    return 0;
}

/**
 * @brief  获取模型个数
 * @param  null
 * @retval null
 */
int get_model_count(void)
{
    ll_t *list = model_list;

    return list->len;
}

/**
 * @brief  获取模型名
 * @param  null
 * @retval null
 */
int get_model_name_by_index(int index, char *name)
{
    struct model_list_node_s *p;
    ll_t *list = model_list;

    if (index > list->len)
        return -1;

    p = (struct model_list_node_s *)ll_get_n(list, index);
    if (NULL == p)
        return -2;

    memcpy(name, p->model_name, strlen(p->model_name));

    return 0;
}

/**
 * @brief  获取某个设备的所有实时数据
 * @param  model 模型名
 * @param  dev 设备名
 * @param  jn json格式返回实时数据
 * @retval null
 */
int get_one_dev_realtime_data(char *model, char *dev, cJSON *jn)
{
    ll_t *list = model_list;
    struct model_list_node_s *p;
    int size;
    int size1;
    int i;
    int j;
    int k;
    // int flag = 0;

    if ((NULL == model) || (NULL == dev) || (NULL == jn))
        return -1;

    if (NULL == list)
        return -2;

    for (i = 0; i < list->len; i++)
    {
        p = (struct model_list_node_s *)ll_get_n(list, i);
        if ((p) && (0 == memcmp(p->model_name, model, strlen(model))) && (strlen(model) == strlen(p->model_name)))
        {
            /* 模型名找到 */
            // printf("func(%s) model[%s] found \n", __FUNCTION__, model);
            if (NULL != p->jn_realtime_data)
            {
                size = cJSON_GetArraySize(p->jn_realtime_data);
                for (j = 0; j < size; j++)
                {
                    cJSON *item = cJSON_GetArrayItem(p->jn_realtime_data, j);
                    if (NULL != item)
                    {
                        cJSON *dev_item = cJSON_GetObjectItemCaseSensitive(item, STR_DEV);
                        if ((0 == memcmp(dev_item->valuestring, dev, strlen(dev))) &&
                            (strlen(dev) == strlen(dev_item->valuestring)))
                        {
                            /* 设备找到 */
                            // printf("func(%s) model[%s] dev[%s] found \n", __FUNCTION__, model, dev);
                            size1 = cJSON_GetArraySize(item);    // item为json对象，非数组，但是也可以用这种方法
                            // for (k = 0; k < size1; k++)
                            for (k = 1; k < size1; k++)
                            {
                                // cJSON *property_item = cJSON_GetArrayItem(item, k + 1); /* 跳过第一个item是"dev" */
                                cJSON *property_item = cJSON_GetArrayItem(item, k);
                                cJSON *val_item = cJSON_GetObjectItemCaseSensitive(property_item, STR_VAL);
                                cJSON *quality_item = cJSON_GetObjectItemCaseSensitive(property_item, STR_QUALITY);
                                cJSON *timestamp_item = cJSON_GetObjectItemCaseSensitive(property_item, STR_TIMESTAMP);
                                if ((NULL == val_item) || (NULL == quality_item) || (NULL == timestamp_item))
                                {
                                    continue;
                                }

                                cJSON *object = cJSON_CreateObject();
                                cJSON_AddItemToObject(object, STR_NAME, cJSON_CreateString(property_item->string));
                                cJSON_AddItemToObject(object, STR_VAL, cJSON_CreateString(val_item->valuestring));
                                cJSON_AddItemToObject(object, STR_QUALITY,
                                                      cJSON_CreateString(quality_item->valuestring));
                                cJSON_AddItemToObject(object, STR_TIMESTAMP,
                                                      cJSON_CreateString(timestamp_item->valuestring));
                                cJSON_AddItemToArray(jn, object);
                            }
                        }
                    }
                }
            }
        }
    }

    return 0;
}

/**
 * @brief  获取某个设备的某个属性的实时数据
 * @param  model 模型名
 * @param  dev 设备名
 * @param  dev 属性名
 * @param  jn json格式返回实时数据
 * @retval null
 */
int get_dev_one_realtime_data(char *model, char *dev, char *property, cJSON *jn)
{
    ll_t *list = model_list;
    struct model_list_node_s *p;
    int size;
    int size1;
    int i;
    int j;
    int k;
    // int flag = 0;

    if ((NULL == model) || (NULL == dev) || (NULL == jn))
        return -1;

    if (NULL == list)
        return -2;

    for (i = 0; i < list->len; i++)
    {
        p = (struct model_list_node_s *)ll_get_n(list, i);
        if ((p) && (0 == memcmp(p->model_name, model, strlen(model))) && (strlen(model) == strlen(p->model_name)))
        {
            /* 模型名找到 */
            // printf("func(%s) model[%s] found \n", __FUNCTION__, model);
            if (NULL != p->jn_realtime_data)
            {
                size = cJSON_GetArraySize(p->jn_realtime_data);
                for (j = 0; j < size; j++)
                {
                    cJSON *item = cJSON_GetArrayItem(p->jn_realtime_data, j);
                    if (NULL != item)
                    {
                        cJSON *dev_item = cJSON_GetObjectItemCaseSensitive(item, STR_DEV);
                        if ((0 == memcmp(dev_item->valuestring, dev, strlen(dev))) &&
                            (strlen(dev) == strlen(dev_item->valuestring)))
                        {
                            /* 设备找到 */
                            // printf("func(%s) model[%s] dev[%s] found \n", __FUNCTION__, model, dev);
                            size1 = cJSON_GetArraySize(item);
                            for (k = 0; k < size1; k++)
                            {
                                cJSON *property_item = cJSON_GetArrayItem(item, k + 1); /* 跳过第一个item是"dev" */
                                cJSON *val_item = cJSON_GetObjectItemCaseSensitive(property_item, STR_VAL);
                                cJSON *quality_item = cJSON_GetObjectItemCaseSensitive(property_item, STR_QUALITY);
                                cJSON *timestamp_item = cJSON_GetObjectItemCaseSensitive(property_item, STR_TIMESTAMP);
                                if ((NULL == val_item) || (NULL == quality_item) || (NULL == timestamp_item))
                                {
                                    return 0;
                                }
                                if ((0 == memcmp(property_item->string, property, strlen(property))) &&
                                    (strlen(property) == strlen(property_item->string)))
                                {
                                    cJSON *object = cJSON_CreateObject();
                                    cJSON_AddItemToObject(object, STR_NAME, cJSON_CreateString(property_item->string));
                                    cJSON_AddItemToObject(object, STR_VAL, cJSON_CreateString(val_item->valuestring));
                                    cJSON_AddItemToObject(object, STR_QUALITY,
                                                          cJSON_CreateString(quality_item->valuestring));
                                    cJSON_AddItemToObject(object, STR_TIMESTAMP,
                                                          cJSON_CreateString(timestamp_item->valuestring));
                                    cJSON_AddItemToArray(jn, object);
                                    return 0; /* 成功找到某个属性的信息 */
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    return 0;
}

/**
 * @brief  调试查看所有设备实时数据（jn_realtime_data）
 * @param  null
 * @retval null
 */
int print_jn_realtime_data(void)
{
    ll_t *list = model_list;
    struct model_list_node_s *p;
    int i;

    if (NULL == list)
        return -1;

    for (i = 0; i < list->len; i++)
    {
        p = (struct model_list_node_s *)ll_get_n(list, i);

        char *payload = cJSON_Print(p->jn_realtime_data);
        printf("func(%s) realtime_data = %s \n", __FUNCTION__, payload);
        if (payload)
            cJSON_free(payload);
    }

    return 0;
}

/**
 * @brief  API调试查看所有设备实时数据（jn_realtime_data）
 * @param  null
 * @retval null
 */
int api_print_jn_realtime_data(char *app, char *tpc, char *msg, char *response)
{
    print_jn_realtime_data();

    return 0;
}

/**
 * @brief  写入设备实时数据到内存（jn_realtime_data）
 * @param  model 模型名
 * @param  dev 设备名
 * @param  name 属性名
 * @param  val 属性值
 * @param  quality
 * @param  index
 * @param  timestamp
 * @retval null
 */
int save_dev_realtime_data(char *model, char *dev, char *name, char *val, char *quality, char *index, char *timestamp)
{
    ll_t *list = model_list;
    struct model_list_node_s *p;
    int size;
    int i;
    int j;
    int flag = 0;

    if ((NULL == model) || (NULL == dev) || (NULL == name) || (NULL == val) || (NULL == timestamp))
    {
        return -1;
    }

    if (NULL == list)
        return -2;

    for (i = 0; i < list->len; i++)
    {
        p = (struct model_list_node_s *)ll_get_n(list, i);
        if ((p) && (0 == memcmp(p->model_name, model, strlen(model))) && (strlen(model) == strlen(p->model_name)))
        {
            /* 模型名找到 */
            // printf("func(%s) model[%s] found \n", __FUNCTION__, model);
            if (NULL != p->jn_realtime_data)
            {
                size = cJSON_GetArraySize(p->jn_realtime_data);
                for (j = 0; j < size; j++)
                {
                    cJSON *item = cJSON_GetArrayItem(p->jn_realtime_data, j);
                    if (NULL != item)
                    {
                        cJSON *dev_item = cJSON_GetObjectItemCaseSensitive(item, STR_DEV);
                        if ((0 == memcmp(dev_item->valuestring, dev, strlen(dev))) &&
                            (strlen(dev) == strlen(dev_item->valuestring)))
                        {
                            /* 设备找到 */
                            // printf("func(%s) model[%s] dev[%s] found \n", __FUNCTION__, model, dev);
                            cJSON *name_item = cJSON_GetObjectItemCaseSensitive(item, name);
                            if (NULL != name_item)
                            {
                                /* 设备的属性找到 */
                                // printf("func(%s) model[%s] dev[%s] name[%s] found \n", __FUNCTION__, model, dev,
                                // name);
                                cJSON_ReplaceItemInObject(name_item, STR_VAL, cJSON_CreateString(val));
                                if (NULL != quality)
                                {
                                    cJSON_ReplaceItemInObject(name_item, STR_QUALITY, cJSON_CreateString(quality));
                                }
                                if (NULL != index)
                                {
                                    cJSON_ReplaceItemInObject(name_item, STR_INDEX, cJSON_CreateString(index));
                                }
                                cJSON_ReplaceItemInObject(name_item, STR_TIMESTAMP, cJSON_CreateString(timestamp));
                                flag = 1;
                            }
                            else
                            {
                                /* 设备的属性没找到 */
                                LOG_PRINTF_ERROR( "func(%s) cant find name[%s] in model[%s] dev[%s]",
                                           __FUNCTION__, name, model, dev);
                            }
                        }
                    }
                }
            }
        }
    }

    // print_jn_realtime_data(); /* 测试 */

    if (flag)
    {
        return 0;
    }
    else
    {
        return -3;
    }
}

/**
 * @brief  删除数据库中某个表
 * @param  null
 * @retval null
 */
int delete_table(char *table_name)
{
    char str_sql[256];
    int rtn = 0;

    if (NULL == table_name)
        return -1;

    log_printf(MSG_WARNING, "deleting table %s", table_name);

    if (table_exist_check(table_name) > 0)
    {
        memset(str_sql, 0x00, sizeof(str_sql));
        sprintf(str_sql, DELETE_TABLE, table_name);
        rtn = db_delete_table(str_sql);
        if (rtn < 0)
        {
            LOG_PRINTF_ERROR( "delete table: %s error[%d]", table_name, rtn);
        }
        else
        {
            log_printf(MSG_WARNING, "delete table: %s ok", table_name);
            // // 删除完数据表后执行空间释放
            // if(db_vacuum() != 0)
            // {
            //     LOG_PRINTF_ERROR( "vacuum database error");
            // }
        }
    }

    return rtn;
}

/**
 * @brief  删除某个表的某一项
 * @param  null
 * @retval null
 */
int delete_table_one_item(char *table_name, char *item_key, char *item_val)
{
    char str_sql[256];
    int rtn;

    if ((NULL == table_name) || (NULL == item_key) || (NULL == item_val))
        return -1;

    log_printf(MSG_WARNING, "delete %s = %s from table[%s]", item_key, item_val, table_name);

    memset(str_sql, 0x00, sizeof(str_sql));
    sprintf(str_sql, DELETE_TABLE_ONE_ITEM, table_name, item_key, item_val);
    rtn = db_delete_table(str_sql);
    if (rtn)
    {
        LOG_PRINTF_ERROR( "delete %s = %s from table[%s]", item_key, item_val, table_name);
    }

    return rtn;
}

/**
 * @brief  获取模型表中的所有信息，并存储为json格式，jn_model作为指针
 * @param  null
 * @retval null
 */
int get_all_model_info(void)
{
    ll_t *list = model_list;
    struct model_list_node_s *p;
    char name[128];
    int i;

    if (NULL == list)
        return -1;

    for (i = 0; i < list->len; i++)
    {
        p = (struct model_list_node_s *)ll_get_n(list, i);
        if (strlen(p->model_name))
        {
            p->jn_model = cJSON_CreateArray();
            memset(name, 0x00, sizeof(name));
            sprintf(name, "%s%s", STR_MODE_, p->model_name);
            get_mode_info(name, p->jn_model);
#if 0 /* 调试 */
            char *payload = cJSON_Print(p->jn_model);
            printf("%s model info = %s \n", name, payload);
            if (payload) cJSON_free(payload);
#endif
        }
    }

    return 0;
}

/**
 * @brief  获取模型名，并创建model_list_node存储
 * @param  null
 * @retval null
 */
int get_model_list(void)
{
    cJSON *jn = cJSON_CreateArray();
    char *payload;
    int size;
    int i;

    get_all_mode_name(jn);

    payload = cJSON_Print(jn);
    log_printf(MSG_VERBOSE, "func(%s) %s", __FUNCTION__, payload);

    size = cJSON_GetArraySize(jn);

    for (i = 0; i < size; i++)
    {
        cJSON *item = cJSON_GetArrayItem(jn, i);
        if ((NULL == item) || (NULL == item->valuestring))
        {
            continue;
        }

        creat_model_list_node(item->valuestring);
    }

    if (payload)
        cJSON_free(payload);

    if(jn)
    {
        cJSON_Delete(jn);
        jn = NULL;
    }

    return 0;
}

/**
 * @brief  模型注册后，需要调用这个函数，更新单个模型的所有设备的实时数据
 * @param  null
 * @retval null
 */
int update_one_model_all_dev_realtime_data(char *model_name)
{
    ll_t *list = model_list;
    struct model_list_node_s *p;
    char name[128];
    char guid[128];
    int column = 0;
    int i;
    int j;

    if (NULL == list)
        return -1;

    for (i = 0; i < list->len; i++)
    {
        p = (struct model_list_node_s *)ll_get_n(list, i);
        if ((NULL != p) && (strlen(p->model_name) == strlen(model_name)) &&
            (0 == memcmp(p->model_name, model_name, strlen(model_name))))
        {
            if (p->jn_realtime_data)
            {
                cJSON_Delete(p->jn_realtime_data);
                p->jn_realtime_data = NULL;
            }
            p->jn_realtime_data = cJSON_CreateArray();
            memset(name, 0x00, sizeof(name));
            sprintf(name, "%s%s", STR_DEV_, p->model_name);
            get_table_column(name, &column);
            // printf("func(%s) table[%s] column = %d \n", __FUNCTION__, name, column);
            for (j = 0; j < column; j++)
            {
                memset(guid, 0x00, sizeof(guid));
                get_dev_guid_one_by_one(name, j, guid);
                // printf("func(%s) guid = %s \n", __FUNCTION__, guid);
                if (strlen(guid))
                {
                    cJSON *object = cJSON_CreateObject();
                    char buff[128];
                    memset(buff, 0x00, sizeof(buff));
                    sprintf(buff, "%s_%s", p->model_name, guid);
                    cJSON_AddItemToObject(object, STR_DEV, cJSON_CreateString(buff));
                    /* 添加所有模型的属性到设备实时数据json */
                    add_model_property_to_realtime_data(p->jn_model, object);
                    cJSON_AddItemToArray(p->jn_realtime_data, object);
                }
            }
        }

#if 0 /* 调试 */
        char *payload = cJSON_Print(p->jn_realtime_data);
        printf("func(%s) %s realtime_data = %s \n", __FUNCTION__, name, payload);
        if (payload) cJSON_free(payload);
#endif
    }

    return 0;
}

/**
 * @brief  模型注册后，需要调用这个函数，添加模型信息到model_list，模型注册支持分包
 * @param  null
 * @retval null
 */
int update_model_list_when_model_regist(char *model_name)
{
    ll_t *list = model_list;
    struct model_list_node_s *p;
    char name[128];
    int i;
    int rtn = -2;
    // char flag = 0;

    if ((NULL == list) || (NULL == model_name))
        return -1;

    for (i = 0; i < list->len; i++)
    {
        p = (struct model_list_node_s *)ll_get_n(list, i);
        if ((NULL != p) && (strlen(p->model_name) == strlen(model_name)) &&
            (0 == memcmp(p->model_name, model_name, strlen(model_name))))
        {
            /* 为了兼容分包注册模型，每次先从内存删除，后更从数据库更新 */
            ll_remove_n(list, i);
        }
    }

    creat_model_list_node(model_name);

    for (i = 0; i < list->len; i++)
    {
        p = (struct model_list_node_s *)ll_get_n(list, i);
        if ((NULL != p) && (strlen(p->model_name) == strlen(model_name)) &&
            (0 == memcmp(p->model_name, model_name, strlen(model_name))))
        {
            p->jn_model = cJSON_CreateArray();
            p->jn_dev = cJSON_CreateArray();
            p->jn_realtime_data = cJSON_CreateArray();
            p->jn_soe_subscribe = cJSON_CreateArray();
            memset(name, 0x00, sizeof(name));
            sprintf(name, "%s%s", STR_MODE_, p->model_name);
            get_mode_info(name, p->jn_model);
            update_one_model_all_dev_realtime_data(p->model_name);
            rtn = 0;
#if 0 /* 调试 */
            char *payload = cJSON_Print(p->jn_model);
            printf("%s model info = %s \n", name, payload);
            if (payload) cJSON_free(payload);
#endif
        }
    }

    return rtn;
}

/**
 * @brief  模型删除后，需要调用这个函数，从model_list删除模型信息
 * @param  null
 * @retval null
 */
int update_model_list_when_model_unregist(char *model_name)
{
    int i;
    struct model_list_node_s *p;
    ll_t *list = model_list;

    if ((NULL == list) || (NULL == model_name))
        return -1;

    for (i = 0; i < list->len; i++)
    {
        p = (struct model_list_node_s *)ll_get_n(list, i);
        if ((NULL != p) && (strlen(p->model_name) == strlen(model_name)) &&
            (0 == memcmp(p->model_name, model_name, strlen(model_name))))
        {
            if (NULL != p->jn_dev)
            {
                cJSON_Delete(p->jn_dev);
                p->jn_dev = NULL;
            }
            if (NULL != p->jn_model)
            {
                cJSON_Delete(p->jn_model);
                p->jn_model = NULL;
            }
            if (NULL != p->jn_realtime_data)
            {
                cJSON_Delete(p->jn_realtime_data);
                p->jn_realtime_data = NULL;
            }

            if (NULL != p->jn_soe_subscribe)
            {
                cJSON_Delete(p->jn_soe_subscribe);
                p->jn_soe_subscribe = NULL;
            }

            free(p);
            p = NULL;
            ll_remove_n(model_list, i);
            break;
        }
    }

    return 0;
}

#if 0
/**
  * @brief  设备注册或取消注册后，需要调用这个函数，更新模型下所有设备的实时数据到model_list
  * @param  model_name 需要更新实时数据的模型名
  * @retval null
  */
int update_model_list_when_dev_regist_unregist(char *model_name)
{
    ll_t *list = model_list;
    struct model_list_node_s *p;
    char name[128];
    char guid[128];
    int column;
    int i;
    int j;

    if ((NULL == list) || (NULL == model_name)) return -1;

    for (i = 0; i < list->len; i++) {
        p = (struct model_list_node_s *)ll_get_n(list, i);
        if ((NULL != p) && (0 == memcmp(p->model_name, model_name, strlen(model_name))) && (strlen(p->model_name) == strlen(model_name))) {
            if(NULL != p->jn_realtime_data) {
                /* 先删除 */
                cJSON_Delete(p->jn_realtime_data);
                p->jn_realtime_data = NULL;
            }
            /* 再重新创建，重新到设备表中获取所有设备的实时数据 */
            p->jn_realtime_data = cJSON_CreateArray();
            memset(name, 0x00, sizeof(name));
            sprintf(name, "%s%s", STR_DEV_, p->model_name);
            get_table_column(name, &column);
            //printf("func(%s) table[%s] column = %d \n", __FUNCTION__, name, column);
            for (j = 0; j < column; j++) {
                memset(guid, 0x00, sizeof(guid));
                get_dev_guid_one_by_one(name, j, guid);
                //printf("func(%s) guid = %s \n", __FUNCTION__, guid);
                if (strlen(guid)) {
                    cJSON *object = cJSON_CreateObject();
                    char buff[128];
                    memset(buff, 0x00, sizeof(buff));
                    sprintf(buff, "%s_%s", p->model_name, guid);
                    cJSON_AddItemToObject(object, STR_DEV, cJSON_CreateString(buff));
                    /* 添加所有模型的属性到设备实时数据json */
                    add_model_property_to_realtime_data(p->jn_model, object);
                    cJSON_AddItemToArray(p->jn_realtime_data, object);
                }
            }
            break;
        }

#if 0 /* 调试 */
        char *payload = cJSON_Print(p->jn_realtime_data);
        printf("func(%s) %s realtime_data = %s \n", __FUNCTION__, name, payload);
        if (payload) cJSON_free(payload);
#endif
    }

    return 0;
}
#else
/**
 * @brief  设备注册或取消注册后，需要调用这个函数，更新模型下所有设备的实时数据到model_list
 * @param  model_name 需要更新实时数据的模型名
 * @param  dev_name 需要更新实时数据的设备名
 * @param  mode 1设备注册，0设备取消注册
 * @retval null
 */
int update_model_list_when_dev_regist_unregist(char *model_name, char *dev_name, int mode)
{
    ll_t *list = model_list;
    struct model_list_node_s *p;
    int i;
    int j;
    int size;
    int flag = 0;

    if ((NULL == list) || (NULL == model_name))
        return -1;
    if ((0 != mode) && (1 != mode))
        return -1;

    for (i = 0; i < list->len; i++)
    {
        p = (struct model_list_node_s *)ll_get_n(list, i);
        if ((NULL != p) && (0 == memcmp(p->model_name, model_name, strlen(model_name))) &&
            (strlen(p->model_name) == strlen(model_name)))
        {
            size = cJSON_GetArraySize(p->jn_realtime_data);
            // printf("func(%s) cJSON_GetArraySize = %d \n", __FUNCTION__, size);
            for (j = 0; j < size; j++)
            {
                cJSON *item = cJSON_GetArrayItem(p->jn_realtime_data, j);
                cJSON *dev_item = cJSON_GetObjectItemCaseSensitive(item, STR_DEV);
                if ((0 == dev_item) || (0 == dev_item->valuestring) || (0 == strlen(dev_item->valuestring)))
                {
                    continue;
                }
                // printf("%s = %s \n", STR_DEV, dev_item->valuestring);
                if ((0 == memcmp(dev_item->valuestring, dev_name, strlen(dev_name))) &&
                    (strlen(dev_item->valuestring) == strlen(dev_name)))
                {
                    flag = 1;
                    break;
                }
            }
            // printf("flag = %d, mode = %d \n", flag, mode);
            if ((flag == 1) && (0 == mode))
            {
                /* 设备取消注册 */
                cJSON *temp = cJSON_Duplicate(p->jn_realtime_data, 1);
                cJSON_DeleteItemFromArray(temp, j);
                cJSON_Delete(p->jn_realtime_data);
                p->jn_realtime_data = cJSON_Duplicate(temp, 1);
                cJSON_Delete(temp);
            }
            else if ((flag == 0) && (1 == mode))
            {
                /* 设备注册 */
                cJSON *object = cJSON_CreateObject();
                cJSON_AddItemToObject(object, STR_DEV, cJSON_CreateString(dev_name));
                /* 添加所有模型的属性到设备实时数据json */
                add_model_property_to_realtime_data(p->jn_model, object);
                cJSON_AddItemToArray(p->jn_realtime_data, object);
            }
#if 0 /* 调试 */
            char *payload = cJSON_Print(p->jn_realtime_data);
            printf("func(%s) %s realtime_data = %s \n", __FUNCTION__, model_name, payload);
            if (payload) cJSON_free(payload);
#endif
            break;
        }
    }

    return 0;
}
#endif

/**
 * @brief  获取历史记录最大保存天数
 * @param  null
 * @retval null
 */
int get_db_history_log_day(void)
{
    return db_config.history_log_day;
}

static int select_cb(void *para, int argc, char **argv, char **azColName) 
{
    int i;
    // int count;

    printf("column = %d \n", argc);
    for (i = 0; i < argc; i++)
    {
        printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
    }
    printf("\n");

    return 0;
}

/**
 * @brief  数据库运行状态机
 * @param  null
 * @retval null
 */
int database_run(void)
{
    static int db_state = E_DB_INIT;
    int iret = -1;
    // int i = 0;
    char *db_file = db_config.database_dir;
    // struct db_name_list *p_d_l;
    // int count;

    switch (db_state)
    {
    case E_DB_INIT: {
        if (0 != file_exist(db_file))
        {
            /* 数据库文件不存在 */
            LOG_PRINTF_ERROR( "%s not exists", db_file);
            sleep(10);
            return -1;
        }

        iret = api_open_sqlite(&g_db, db_file);
        if (0 != iret)
        {
            LOG_PRINTF_ERROR( "%s open err", db_file);
            sleep(2);
            return -2;
        }

        db_state = E_DB_DEV_LIST;
    }
    break;

    case E_DB_DEV_LIST: {
        model_list_init();
        get_model_list();
        get_all_model_info();
        get_dev_realtime_data();

        db_state = E_DB_DEV_ATTR;
    }
    break;

    case E_DB_DEV_ATTR: {
        db_state = E_DB_RUN;
    }
    break;

    case E_DB_RUN: {
        sleep(1);
    }
    break;

    default:
        db_state = E_DB_INIT;
        break;
    }

    return 0;
}

/**
 * @brief  显式开启事务
 * @param  nulll
 * @retval null
 */
int db_begin(void)
{
    if (NULL == g_db)
    {
        return -1;
    }

    return api_begin_sqlite(g_db);
}

/**
 * @brief  显式开启事务
 * @param  nulll
 * @retval null
 */
int db_commit(void)
{
    if (NULL == g_db)
    {
        return -1;
    }

    return api_commit_sqlite(g_db);
}

/**
 * @brief  VACUUM
 * 命令通过复制主数据库中的内容到一个临时数据库文件，然后清空主数据库，并从副本中重新载入原始的数据库文件。这消除了空闲页，把表中的数据排列为连续的，另外会清理数据库文件结构。
 * @param  nulll
 * @retval null
 */
int db_vacuum(void)
{
    if (NULL == g_db)
    {
        return -1;
    }

    return api_vacuum_sqlite(g_db);
}

/**
 * @brief  添加一项到数据库表
 * @param  t_name 历史表名
 * @retval null
 */
int db_insert_into_table(char *str_sql)
{
    int iret;

    if (NULL == g_db)
    {
        return -1;
    }

    if (NULL == str_sql)
    {
        return -2;
    }

    iret = api_insert_sqlite(g_db, str_sql);
    if (0 != iret)
    {
        LOG_PRINTF_ERROR( "%s err", str_sql);
        return -3;
    }

    return 0;
}

/**
 * @brief  添加一项到数据库表
 * @param  t_name 历史表名
 * @retval null
 */
int db_update_into_table(char *str_sql)
{
    int iret;

    if (NULL == g_db)
    {
        return -1;
    }

    if (NULL == str_sql)
    {
        return -2;
    }

    iret = api_update_sqlite(g_db, str_sql);
    if (0 != iret)
    {
        LOG_PRINTF_ERROR( "%s err", str_sql);
        return -3;
    }

    return 0;
}

/**
 * @brief  获取表中下一个sn（是主键）的值的函数的回调函数
 * @param  null
 * @retval null
 */
static int get_next_primary_key_cb(void *para, int argc, char **argv, char **azColName)
{
    // int i;

    if (NULL == para)
        return 0;

    *(int *)para = atoi(argv[0]);

    return 0;
}

/**
 * @brief  获取表中下一个sn（是主键）的值
 * @param  t_name 表名
 * @param  t_num 返回的sn值
 * @retval null
 */
int get_next_serial_num(char *t_name, int *p_num)
{
    int iret;
    char buff[1024];
    int num;

    if (NULL == g_db)
    {
        return -1;
    }

    if (NULL == t_name)
    {
        return -2;
    }

    memset(buff, 0x00, sizeof(buff));
    sprintf(buff, SELECT_TALBE_GET_COUNT, "sn", t_name);
    // printf("get_next_serial_num = %s \n", buff);
    num = 0;
    iret = api_select_sqlite(g_db, buff, get_next_primary_key_cb, (void *)&num);
    if (0 != iret)
    {
        return -3;
    }
    *p_num = num + 1;
    // printf("get_next_serial_num = %d \n", *p_num);

    return 0;
}

/**
 * @brief  删除表，可以是整张表，也可以是表中的某条数据，取决于str_sql
 * @param  str_sql 删除表的sql语句
 * @retval null
 */
int db_delete_table(char *str_sql)
{
    int iret;

    if (NULL == g_db)
    {
        return -1;
    }

    if (NULL == str_sql)
    {
        return -2;
    }

    iret = api_delete_sqlite(g_db, str_sql);
    if (0 != iret)
    {
        LOG_PRINTF_ERROR( "%s err", str_sql);
        return -3;
    }

    return 0;
}

/**
 * @brief  执行数据库的select操作并带callback函数
 * @param  str_sql sql语句
 * @param  cb_fun callback函数
 * @param  para callback函数的第一个形参
 * @retval null
 */
int db_select_with_cb(char *str_sql, sqlite3_callback cb_fun, void *para)
{
    int iret;

    if (NULL == g_db)
    {
        return -1;
    }

    if (NULL == str_sql)
    {
        return -2;
    }

    iret = api_select_sqlite(g_db, str_sql, cb_fun, para);

    if (0 != iret)
    {
        LOG_PRINTF_ERROR( "%s err", str_sql);
        return -3;
    }

    return 0;
}

/**
 * @brief  获取log配置信息
 * @param  null
 * @retval null
 */
int get_log_config(int *en, int *mbyte, int *rsyslog_enable)
{
    *rsyslog_enable = db_config.rsyslog_enable;
    *en = db_config.log_file_enable;
    *mbyte = db_config.log_file_size_max_mbyte;

    return 0;
}

/**
 * @brief  读取json配置文件
 * @param  null
 * @retval null
 */
int read_json_config(void)
{
    int ret = 0;
    cJSON *config_json = NULL;
    cJSON *db_item = NULL, *n_item = NULL;
    char *json = NULL;

    memset(&db_config, 0x00, sizeof(db_config));

    json = read_file(CONFIG_PATH_JSON);
    if ((json == NULL) || (json[0] == '\0') || (json[1] == '\0'))
    {
        ret = -1;
        goto cleanup;
    }

    config_json = cJSON_Parse(json);
    if (config_json == NULL)
    {
        ret = -2;
        goto cleanup;
    }

    printf("\ndatabase_config---------------------------------- \n");

    /* get database config value */
    db_item = cJSON_GetObjectItemCaseSensitive(config_json, "database_config");
    if (db_item == NULL)
    {
        ret = -3;
        goto cleanup;
    }

    /* mqtt_broker地址 */
    n_item = cJSON_GetObjectItemCaseSensitive(db_item, "mqtt_broker");
    if ((n_item == NULL) || (strlen(n_item->valuestring) < 0) ||
        (strlen(n_item->valuestring) >= sizeof(db_config.mqtt_broker)))
    {
        LOG_PRINTF_ERROR( "mqtt_broker config error");
        ret = -3;
        goto cleanup;
    }
    strcpy(db_config.mqtt_broker, n_item->valuestring);
    printf("mqtt_broker = %s \n", db_config.mqtt_broker);

    /* database文件路径 */
    n_item = cJSON_GetObjectItemCaseSensitive(db_item, "database_dir");
    if ((n_item == NULL) || (strlen(n_item->valuestring) < 0) ||
        (strlen(n_item->valuestring) >= sizeof(db_config.database_dir)))
    {
        LOG_PRINTF_ERROR( "database_dir config error");
        ret = -3;
        goto cleanup;
    }
    strcpy(db_config.database_dir, n_item->valuestring);
    printf("database_dir = %s \n", db_config.database_dir);

    /* 最多保存多少天的历史记录 */
    n_item = cJSON_GetObjectItemCaseSensitive(db_item, "history_log_day");
    if (n_item == NULL)
    {
        ret = -3;
        goto cleanup;
    }
    if (n_item->valueint)
    {
        db_config.history_log_day = n_item->valueint;
    }
    else
    {
        /* 配置文件中读取到的为0，天数必须大于0，因此使用默认值 */
        db_config.history_log_day = db_config_default.history_log_day;
    }
    printf("history_log_day = %d \n", db_config.history_log_day);

    /* time_zone */
    n_item = cJSON_GetObjectItemCaseSensitive(db_item, "time_zone");
    if ((n_item == NULL) || (strlen(n_item->valuestring) < 0) ||
        (strlen(n_item->valuestring) >= sizeof(db_config.time_zone)))
    {
        LOG_PRINTF_ERROR( "time_zone config error");
        strcpy(db_config.time_zone, db_config_default.time_zone);
    }
    else
    {
        strcpy(db_config.time_zone, n_item->valuestring);
    }
    printf("time_zone = %s \n", db_config.time_zone);

    /* rsyslog_enable */
    n_item = cJSON_GetObjectItem(db_item, "rsyslog_enable");
    if (n_item == NULL)
    {
        LOG_PRINTF_ERROR( "rsyslog_enable config error");
        db_config.rsyslog_enable = db_config_default.rsyslog_enable;
    }
    else
    {
        if (1 == n_item->valueint)
        {
            db_config.rsyslog_enable = 1;
        }
        else
        {
            db_config.rsyslog_enable = 0;
        }
    }
    printf("rsyslog_enable = %d \n", db_config.rsyslog_enable);

    /* json_unformatted */
    n_item = cJSON_GetObjectItemCaseSensitive(db_item, "json_unformatted");
    if (n_item == NULL)
    {
        LOG_PRINTF_ERROR( "json_unformatted config error");
        db_config.json_unformatted = db_config_default.json_unformatted;
    }
    else
    {
        if (1 == n_item->valueint)
        {
            db_config.json_unformatted = 1;
        }
        else
        {
            db_config.json_unformatted = 0;
        }
    }
    printf("json_unformatted = %d \n", db_config.json_unformatted);

    /* vacuum_interval */
    n_item = cJSON_GetObjectItemCaseSensitive(db_item, "vacuum_interval");
    if (n_item == NULL)
    {
        ret = -4;
        goto cleanup;
    }

    db_config.vacuum_interval = n_item->valueint;

    printf("vacuum_interval = %d \n", db_config.vacuum_interval);

    db_config.license_flag = 0;

    // printf("license_flag = %d \n", db_config.license_flag);
    printf("------------------------------------------------- \n\n");

cleanup:
    if (config_json != NULL)
    {
        cJSON_Delete(config_json);
        config_json = NULL;
    }
    if (json != NULL)
    {
        free(json);
        json = NULL;
    }

    return ret;
}

/**
 * @brief  数据库线程
 * @param  null
 * @retval null
 */
static void *database_monitor_thread(void *parg)
{
    log_printf(MSG_INFO, "%s create success.", __FUNCTION__);

#if 0 /* 测试mqtt */
    int mqtt_test(void);
    mqtt_test();
#endif

    while (is_app_running())
    {
        database_run();
        usleep(10000);

        // 检查zlog配置文件是否修改
        check_zlog_conf();
        // sleep(1);
    }

    return NULL;
}

/**
 * @brief  数据库初始化
 * @param  null
 * @retval null
 */
void database_init(void)
{
    pthread_t tid;
    int err;

    /* 创建线程 */
    err = pthread_create(&tid, NULL, database_monitor_thread, NULL);

    if (-1 == err)
    {
        LOG_PRINTF_ERROR( "database_monitor_thread create fail.");
    }
}

/**
 * @brief  数据库释放内存
 * @param  null
 * @retval null
 */
void database_destory(void)
{
    if (0 != g_db)
    {
        api_close_sqlite(g_db);
        g_db = 0;
    }

    model_list_destroy();

    log_printf(MSG_INFO, "end database destroy.");
}



/**
 * @brief  PRAGMA temp_store_directory = '/userdata/dgri/app/DataCenter/bin';
 * @param  nulll
 * @retval null
 */
int db_set_temp_store_directory(void)
{
    if (NULL == g_db)
    {
        return -1;
    }

    return api_set_temp_store_directory(g_db);
}
